﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DnPakExplorer.Controls {
	public partial class MyCustomControl : System.Windows.Forms.Control, IEnumerable<MyView> {
		private List<MyView> mViews = new List<MyView>();
		private MyView mHoveredView;
		public MyView mCapturedView;

		public MyCustomControl() {
			InitializeComponent();
		}

		#region View

		public void AddView(MyView view) {
			mViews.Add(view);
			view.Parent = this;
		}

		public void RemoveView(MyView view) {
			mViews.Remove(view);
			view.Parent = null;
		}

		public void RemoveView(int index) {
			MyView view = mViews[index];
			mViews.RemoveAt(index);
			view.Parent = null;
		}

		public MyView GetView(int index) {
			return mViews[index];
		}

		public bool ContainsView(MyView view) {
			return mViews.Contains(view);
		}

		public int ViewCount {
			get { return mViews.Count; }
		}

		public void ForAllView<T>(Action<T> action) where T : MyView {
			foreach (MyView view in this) {
				T t = view as T;
				if (t != null) {
					action.Invoke(t);
				}
			}
		}

		public void ForEachView<T>(ForEachAction<T> action) where T : MyView {
			foreach (MyView view in this) {
				T t = view as T;
				if (t != null && action.Invoke(t)) {
					break;
				}
			}
		}

		public delegate bool ForEachAction<T>(T obj);

		public IEnumerator<MyView> GetEnumerator() {
			return mViews.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}

		#endregion

		#region View Event

		protected override void OnMouseDown(MouseEventArgs e) {
			MyView view = mCapturedView == null ? mViews.Find(v => v.Bounds.Contains(e.Location)):mCapturedView;
			if(view != null)
				view.OnMouseDown(new MouseEventArgs(e.Button, e.Clicks, e.X-view.Position.X, e.Y-view.Position.Y, e.Delta));
			base.OnMouseDown(e);
		}

		protected override void OnMouseMove(MouseEventArgs e) {
			MyView view = mCapturedView == null ? mViews.Find(v => v.Bounds.Contains(e.Location)):mCapturedView;
			if (mHoveredView != null && view != mHoveredView) {
				mHoveredView.OnMouseLeave();
			}

			mHoveredView = view;
			if (mHoveredView != null)
				mHoveredView.OnMouseMove(new MouseEventArgs(e.Button, e.Clicks, e.X-view.Position.X, e.Y-view.Position.Y, e.Delta));
			base.OnMouseMove(e);
		}

		protected override void OnMouseUp(MouseEventArgs e) {
			MyView view = mCapturedView == null ? mViews.Find(v => v.Bounds.Contains(e.Location)):mCapturedView;
			if(view != null)
				view.OnMouseUp(new MouseEventArgs(e.Button, e.Clicks, e.X-view.Position.X, e.Y-view.Position.Y, e.Delta));
			base.OnMouseUp(e);
		}

		protected override void OnMouseLeave(EventArgs e) {
			if (mHoveredView != null) {
				mHoveredView.OnMouseLeave();
				mHoveredView = null;
			}
			base.OnMouseLeave(e);
		}

		protected override void OnMouseCaptureChanged(EventArgs e) {
			if (mCapturedView != null) {
				mCapturedView.OnMouseCaptureChanged(Capture);
				if (!Capture) {
					mCapturedView = null;
				}
			}
			base.OnMouseCaptureChanged(e);
		}

		public MyView CapturedView {
			get { return mCapturedView; }
			set {
				if (value == null) {
					Capture = false;
				} else if(mCapturedView != value){
					if (mCapturedView != null) {
						mCapturedView.OnMouseCaptureChanged(false);
						mCapturedView = null;
					}

					mCapturedView = value;
					bool oldc = Capture;
					Capture = true;
					if (oldc)
						mCapturedView.OnMouseCaptureChanged(true);
				}
			}
		}

		#endregion

		protected override void OnPaint(PaintEventArgs pe) {
			base.OnPaint(pe);
			foreach (MyView view in mViews) {
				if (pe.Graphics.Clip.IsVisible(view.Bounds)) {
					float dx = view.Position.X;
					float dy = view.Position.Y;
					pe.Graphics.TranslateTransform(dx, dy);
					view.OnDraw(pe.Graphics);
					pe.Graphics.TranslateTransform(-dx, -dy);
				}
			}
		}

		
	}

	public class MyView {

		public Point Position;
		public Size Size;

		private bool mCaptured;

		public Rectangle Bounds {
			get { return new Rectangle(Position, Size); }
			set {
				Position = value.Location;
				Size = value.Size;
			}
		}

		public Rectangle ClientRect {
			get { return new Rectangle(0, 0, Size.Width, Size.Height); }
		}

		public bool Capture {
			get { return mCaptured; }
			set { Parent.CapturedView = value?this:null; }
		}

		public MyCustomControl Parent { get; set; }

		public virtual void OnMouseDown(MouseEventArgs e) { }

		public virtual void OnMouseMove(MouseEventArgs e) { }

		public virtual void OnMouseUp(MouseEventArgs e) { }

		public virtual void OnMouseLeave() { }

		public virtual void OnMouseCaptureChanged(bool capture) {
			mCaptured = capture;
		}

		public virtual void OnDraw(Graphics g) { }
	}
}
